/*
 * Copyright (c) 2022 Diemit <598757652@qq.com>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _IT8951_H_
#define _IT8951_H_
#include "stdint.h"
#include "stdbool.h"

/*-----------------------------------------------------------------------
M5EPD
------------------------------------------------------------------------*/

#define M5EPD_PANEL_W 960
#define M5EPD_PANEL_H 540

// 在hcs文件中对应具体的GPIO口
#define M5EPD_EPD_PWR_EN_PIN 5
#define M5EPD_BUSY_PIN 6
#define M5EPD_CS_PIN 7

typedef enum {
    M5EPD_OK = 0,
    M5EPD_BUSYTIMEOUT,
    M5EPD_OUTOFBOUNDS,
    M5EPD_NOTMULTIPLE4,
    M5EPD_OTHERERR
} m5epd_err_t;

typedef enum               //             Typical
{                          //   Ghosting  Update Time  Usage
    UPDATE_MODE_INIT = 0,  // * N/A       2000ms       Display initialization,
    UPDATE_MODE_DU   = 1,  //   Low       260ms        Monochrome menu, text
                           //   input, and touch screen input
    UPDATE_MODE_GC16 = 2,  // * Very Low  450ms        High quality images
    UPDATE_MODE_GL16 =
        3,  // * Medium    450ms        Text with white background
    UPDATE_MODE_GLR16 =
        4,  //   Low       450ms        Text with white background
    UPDATE_MODE_GLD16 =
        5,  //   Low       450ms        Text and graphics with white background
    UPDATE_MODE_DU4 =
        6,  // * Medium    120ms        Fast page flipping at reduced contrast
    UPDATE_MODE_A2 = 7,  //   Medium    290ms        Anti-aliased text in menus
                         //   / touch and screen input
    UPDATE_MODE_NONE = 8
} m5epd_update_mode_t;  // The ones marked with * are more commonly used

/*-----------------------------------------------------------------------
IT8951 Command defines
------------------------------------------------------------------------*/

//Built in I80 Command Code
#define IT8951_TCON_SYS_RUN         0x0001
#define IT8951_TCON_STANDBY         0x0002
#define IT8951_TCON_SLEEP           0x0003
#define IT8951_TCON_REG_RD          0x0010
#define IT8951_TCON_REG_WR          0x0011

#define IT8951_TCON_MEM_BST_RD_T    0x0012
#define IT8951_TCON_MEM_BST_RD_S    0x0013
#define IT8951_TCON_MEM_BST_WR      0x0014
#define IT8951_TCON_MEM_BST_END     0x0015

#define IT8951_TCON_LD_IMG          0x0020
#define IT8951_TCON_LD_IMG_AREA     0x0021
#define IT8951_TCON_LD_IMG_END      0x0022

//I80 User defined command code
#define IT8951_I80_CMD_DPY_AREA     0x0034
#define IT8951_I80_CMD_GET_DEV_INFO 0x0302
#define IT8951_I80_CMD_DPY_BUF_AREA 0x0037
#define IT8951_I80_CMD_VCOM         0x0039

/*-----------------------------------------------------------------------
 IT8951 Mode defines
------------------------------------------------------------------------*/

//Rotate mode
#define IT8951_ROTATE_0         0
#define IT8951_ROTATE_90        1
#define IT8951_ROTATE_180       2
#define IT8951_ROTATE_270       3

//Pixel mode (Bit per Pixel)
#define IT8951_2BPP             0
#define IT8951_3BPP             1
#define IT8951_4BPP             2
#define IT8951_8BPP             3

//Endian Type
#define IT8951_LDIMG_L_ENDIAN   0
#define IT8951_LDIMG_B_ENDIAN   1

/*-----------------------------------------------------------------------
IT8951 Registers defines
------------------------------------------------------------------------*/
//Register Base Address
#define IT8951_DISPLAY_REG_BASE     0x1000 //Register RW access

//Base Address of Basic LUT Registers
#define IT8951_LUT0EWHR    (IT8951_DISPLAY_REG_BASE + 0x00) //LUT0 Engine Width Height Reg
#define IT8951_LUT0XYR     (IT8951_DISPLAY_REG_BASE + 0x40) //LUT0 XY Reg
#define IT8951_LUT0BADDR   (IT8951_DISPLAY_REG_BASE + 0x80) //LUT0 Base Address Reg
#define IT8951_LUT0MFN     (IT8951_DISPLAY_REG_BASE + 0xC0) //LUT0 Mode and Frame number Reg
#define IT8951_LUT01AF     (IT8951_DISPLAY_REG_BASE + 0x114) //LUT0 and LUT1 Active Flag Reg

//Update Parameter Setting Register
#define IT8951_UP0SR       (IT8951_DISPLAY_REG_BASE + 0x134) //Update Parameter0 Setting Reg
#define IT8951_UP1SR       (IT8951_DISPLAY_REG_BASE + 0x138) //Update Parameter1 Setting Reg
#define IT8951_LUT0ABFRV   (IT8951_DISPLAY_REG_BASE + 0x13C) //LUT0 Alpha blend and Fill rectangle Value
#define IT8951_UPBBADDR    (IT8951_DISPLAY_REG_BASE + 0x17C) //Update Buffer Base Address
#define IT8951_LUT0IMXY    (IT8951_DISPLAY_REG_BASE + 0x180) //LUT0 Image buffer X/Y offset Reg
#define IT8951_LUTAFSR     (IT8951_DISPLAY_REG_BASE + 0x224) //LUT Status Reg (status of All LUT Engines)
#define IT8951_BGVR        (IT8951_DISPLAY_REG_BASE + 0x250) //Bitmap (1bpp) image color table

//System Registers
#define IT8951_SYS_REG_BASE         0x0000

//Address of System Registers
#define IT8951_I80CPCR              (IT8951_SYS_REG_BASE + 0x04)

//Memory Converter Registers
#define IT8951_MCSR_BASE_ADDR       0x0200
#define IT8951_MCSR                 (IT8951_MCSR_BASE_ADDR + 0x0000)
#define IT8951_LISAR                (IT8951_MCSR_BASE_ADDR + 0x0008)

void enableEPDPower();
void disableEPDPower();

m5epd_err_t It8951Init(void);
m5epd_err_t Clear(bool init);
m5epd_err_t WriteFullGram4bpp(const uint8_t *gram);
m5epd_err_t WritePartGram4bpp(uint16_t x, uint16_t y, uint16_t w,
                                uint16_t h, const uint8_t *gram);
m5epd_err_t FillPartGram4bpp(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
                                uint16_t data);
m5epd_err_t SetRotation(uint16_t rotate);
m5epd_err_t SetArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
m5epd_err_t UpdateFull(m5epd_update_mode_t mode);
m5epd_err_t UpdateArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
                           m5epd_update_mode_t mode);
uint16_t UpdateCount(void);
uint8_t GetRotate(void);
uint8_t GetDirection(void);
void ResetUpdateCount(void);
m5epd_err_t CheckAFSR(void);
void SetColorReverse(bool is_reverse);

m5epd_err_t Active(void);
m5epd_err_t StandBy(void);
m5epd_err_t Sleep(void);

m5epd_err_t GetSysInfo(void);
m5epd_err_t WaitBusy();
m5epd_err_t WriteCommand(uint16_t cmd);
m5epd_err_t WriteWord(uint16_t data);
m5epd_err_t WriteReg(uint16_t addr, uint16_t data);
void WriteGramData(uint16_t data);
m5epd_err_t ReadWords(uint16_t *buf, uint32_t length);
m5epd_err_t WriteArgs(uint16_t cmd, uint16_t *args, uint16_t length);
m5epd_err_t SetTargetMemoryAddr(uint32_t tar_addr);

void StartSPI(void);
void EndSPI(void);

#endif